iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0
Modern Web

Fastify 101系列 第 21

[Fastify] Day21 - Cache with Redis

  • 分享至 

  • xImage
  •  

大家好,我是 Yubin

這篇文章跟大家介紹在開發後端網路應用程式的時候,非常重要的環節,快取 (Cache)。


Cache

Cache 快取是什麼?

想像一下,你在第一次瀏覽某個網站的時候,可能圖片載入速度很慢,但當你重新整理頁面或下次再回來這個網站的時候,速度比第一次來的時候還要快。
這是一種快取的應用。

Client Side Cache

瀏覽器載入 HTML, JavaScript, CSS, 或圖片檔案的時候,會根據該 Response 的 HTTP Header 上面的資訊,決定這份資料要快取多久。
講人話,就是把那些資源暫時的記在你的裝置上,當你下次點開網頁要瀏覽相同資源的時候,就不用再發送一次 Request 去要資源,直接拿之前存下來的資料來顯示就可以了。

以網頁應用來說,這類型的快取是 Client 端的快取。
因為資訊的內容是存在 Client 端,也就是使用者的裝置上。

伺服器只要在回應的時候打上正確的 HTTP Header 來描述這個 Response 內容的快取時間,用戶端收到後,可以參考這個時間來決定快取的相關動作。

可以打開開發者工具,觀察網路的頁籤中,有沒有資源被標記為 快取
(在圖片檔的處理特別明顯。)

https://ithelp.ithome.com.tw/upload/images/20221006/20151148xYWK8vuGjQ.jpg

上圖以 PChome 首頁為例。

因為快取的內容是記在用戶端,所以使用者也可以自由地把快取清除或停用。
(如上圖右上角的 停用快取 功能)


先不提使用者端的東西,在 Client 端發送一個 Request 後,經過網路的傳輸,中間可能會經過 CDN。

https://ithelp.ithome.com.tw/upload/images/20221006/20151148XP4HbtanFC.png

CDN

CDN,Content Delivery Network。

想像一個情境,你在台灣,你要瀏覽美國的某個網頁。

距離很遠,網路很慢,中間經過了無數的網路節點,你瀏覽網站的體驗很差。

如果這個時候,在台灣有一台伺服器,他幫你把你想瀏覽的那個網站內容存起來,你要瀏覽網站的時候,那台伺服器就直接把你要看的東西回應給你,而不用跟遠在天邊的那台主機互動,是不是很美好。

那台伺服器就是 CDN Server。

那如果世界上有很多台這樣的伺服器,作為服務提供者,是不是可以讓全世界的人都可以快速看到我提供的內容。

而且如果我自己的伺服器不小心壞掉,或許那些 CDN Server 還可以把內容提供給使用者,讓使用者不會感覺服務中斷。

但要自己假設 CDN 的成本太高了。
(你要怎麼在全世界都有電腦、都有網路、都有維運人員XD)

一般的做法是租用 CDN 的服務,我自己用過覺得滿順手的是 Cloudflare 跟 AWS 的 CloudFront,還有很多其他廠商都有提供 CDN 的服務,這邊不是業配就不多提了。

什麼是 CDN,可以參考這篇 Cloudflare 寫的介紹

Server Side Cache

除了使用者端的 Cache、CDN 以外,在伺服器 Server 端也可以做快取。

例如,你的服務會需要跟第三方的服務拿資源,可是那個服務回應的很慢,那你會不會想把這些回應記下來,下次需要用到的時候直接拿之前存下來的東西,而不去跟那個很花時間的第三方服務拿。

或是 Database 的查詢有夠慢,如果你確定要拿的資料很久才會更新,那就可以考慮建立一個快取伺服器 (Cache Server),把東西存起來,並設定一個合理的過期時間 (expire time),在過期前都拿那份資料來用。

這件事可以靠 Redis 來幫我們輕鬆實現。

Redis

Redis 代表 Remote Dictionary Server,
是快速的開源記憶體內 (in-memory) 鍵值 (key-value) 資料存放區。

最常見的應用就是做快取

因為他活在記憶體中,不像大部分的資料庫會相依於硬碟速度,記憶體的速度遠比硬碟快上許多。

Redis 的應用不只做快取,但本篇會拿來當快取伺服器。
其他應用可以參考這篇的 AWS 寫介紹

Redis Container

要使用 Redis 來進行開發,最方便也最推薦的作法是,起一個 Redis Container。

使用 docker,打開 terminal 敲入:

docker run -d -p 6379:6379 redis

如果使用的是 podman,把 docker run 改為 podman run 即可。

Redis 預設的 port 是 6379

以上指令沒有跳出錯誤訊息就代表本機的 Redis Service 已經起起來了。

@fastify/redis

@fastify/redis 是 Fastify 官方維護的與 Redis 進行互動的 Plugin。

可以透過 npm 來安裝:

npm i @fastify/redis

接著就可以透過 server.register() 方法註冊這個 Plugin。

import fastify, { FastifyInstance } from 'fastify'
import fastifyRedis from '@fastify/redis'

const server: FastifyInstance = fastify()

server.register(fastifyRedis, {
    url: 'redis://127.0.0.1',
    closeClient: true
})

url 帶入 redis 的連線字串。
closeClient 設為 true 表示在 app 關閉時中斷連線,預設為 false

這個 plugin 會在 FastifyInstance 註冊一個名為 redis 的 decorator。

server.get('/hello', async (request, reply) => {
    try {
      const myValue = await server.redis.get('my-key')
      if (myValue) {
        return reply.status(200).send({ message: `Hello ${myValue}` })
      }
      return reply.status(200).send({ message: 'Cache Miss' })
    } catch (error) {
      return reply.status(500).send({ error })
    }
})

透過 server.redis 拿到 Redis Client 物件,就可以使用 .get() 來拿快取的資料,或透過 .set() 來把資料丟入 Redis Server 中。

上述程式範例使用 async/await style,也可以用 callback style 來處理,
可以參考官方文件的用法


本篇介紹了 Cache 在日常中會碰到的點,以及透過 Fastify 官方提供的 Plugin 要怎麼跟 Redis 進行互動。

Cache 是後端非常重要的元件,在系統、架構設計方面就要優先考量的重要存在。

Cache 中定義怎樣的資料才算"髒"的,哪邊應該用,哪邊不應該用,快取資料的 Expire time 要怎麼設定,等等的問題非常多。

曾經有人這麼說過:

https://ithelp.ithome.com.tw/upload/images/20221006/20151148XDwu9z4I7q.jpg

共勉之。


上一篇
[Fastify] Day20 - Mongoose
下一篇
[Fastify] Day22 - Testcontainers
系列文
Fastify 10130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言